package j3dscene;

import com.sun.j3d.utils.picking.PickResult;
import com.sun.j3d.utils.picking.behaviors.PickMouseBehavior;
import java.awt.AWTEvent;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.media.j3d.*;

/**
 * This class implements a pick behaviour. It identifies each picked object and
 * chooses the one with the lowest priority value. When hitting special nodes
 * (crash cymbal, ride cymbal, basedrum/pedal, hihat) it calls the appropriate
 * animation from the Animator class
 *
 * @author Dominik K.
 * @author Steffen G.
 * @version 1.0
 */
public class Picker extends PickMouseBehavior {

    private BranchGroup pickRoot;
    /**
     * The wake up criteria. This is set to trigger on mouse events using the
     * MOUSE_EVENT_MASK.
     */
    WakeupOnAWTEvent buttonPressed =
            new WakeupOnAWTEvent(MouseEvent.MOUSE_EVENT_MASK);

    /**
     * @param pickRoot BranchGroup that is the root of the picking operation.
     * @param pickCanvas Canvas3D used in the pick operation.
     * @param pickBounds Bounds that define the behaviour's active region.
     */
    public Picker(Canvas3D pickCanvas,
            BranchGroup pickRoot, Bounds pickBounds) {
        super(pickCanvas, pickRoot, pickBounds);
        setSchedulingBounds(pickBounds);
        this.pickRoot = pickRoot;
    }

    /**
     * Sets the wake up criterion to the mouse button criteria.
     */
    public void initialize() {
        wakeupOn(buttonPressed);
    }

    /**
     * Where the processing is carried out. This obtains the AWT mouse event,
     * checks if it is the left mouse button and then uses the x and y
     * coodinates of the mouse position to pick an object. A message is printed
     * according to which object has been picked. Finally the wake up condition
     * is set to the mouse criterion again.
     */
    @Override
    public void processStimulus(Enumeration criteria) {
        WakeupOnAWTEvent theCriterion = (WakeupOnAWTEvent) criteria.nextElement();
        AWTEvent theEvents[] = theCriterion.getAWTEvent();
        if (theEvents[0].getID() == MouseEvent.MOUSE_RELEASED) {
            MouseEvent theMouseEvent = (MouseEvent) theEvents[0];
            if ((theMouseEvent.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
                int xpos = theMouseEvent.getX();
                int ypos = theMouseEvent.getY();

                PickResult[] pickResults;
                pickCanvas.setShapeLocation(xpos, ypos);
                pickResults = pickCanvas.pickAllSorted();
                HashMap<Integer, PrioUserData> userDatas =
                        new HashMap<Integer, PrioUserData>();


                if (pickResults != null) {
                    int i = 0;
                    for (PickResult p : pickResults) {
                        Node actShape = (Node) p.getNode(PickResult.SHAPE3D);
                        if (actShape != null) {
                            PrioUserData userData;
                            try {
                                userData = (PrioUserData) actShape.getUserData();
                            } catch (Exception e) {
                                userData = new PrioUserData("noname", 99);
                            }
                            if (userData == null) {
                                userData = new PrioUserData("noname", 99);
                            }

                            int calcPrio = 99;
                            calcPrio = userData.getPriority() * (i + 1);
                            userDatas.put(calcPrio, userData);
                        } else {
                            System.out.println("Aktuelles Shape ist Null");
                        }
                        i++;
                    }
                }
                PrioUserData bestNode = smallestValue(userDatas);
                if (bestNode != null) {
                    System.out.println(bestNode.toString());
                    idk.IDK.getWindow().setPicking(bestNode.getName());
                    
                    if (bestNode.getName().contains("HiHat")
                            && bestNode.getName().contains("Cymbal")) {
                        Animator.animateHiHatOpen();
                    } else if (bestNode.getName().contains("HiHat")
                            && !bestNode.getName().contains("Cymbal")) {
                        Animator.animateHihat();   
                    } else if (bestNode.getName().contains("Bass")
                            && !bestNode.getName().contains("Fuss")) {
                        Animator.animatePedal();
                    } else if (bestNode.getName().contains("Crash")
                            && !bestNode.getName().contains("Stativ")) {
                        Animator.animateCrash();
                    } else if (bestNode.getName().contains("Ride")
                            && !bestNode.getName().contains("Stativ")) {
                        Animator.animateRide();
                    } else if (bestNode.getName().contains("Fussmaschine")) {
                        Animator.animatePedal();
                    } else if (bestNode.getName().contains("Snare")
                            && !bestNode.getName().contains("Stativ")) {
                        Animator.playSnare();
                    } else if (bestNode.getName().contains("Racktom")) {
                        Animator.playRacktom();
                    } else if (bestNode.getName().contains("Floortom")) {
                        Animator.playFloortom();
                    }
                }
            }
        }
        wakeupOn(buttonPressed);
    }

    /**
     * Returns the userdata object with the smallest priority value.
     *
     * @param hm Hashmap containing the priority value and the userdata objects.
     * @return userdata object with smallest priority value.
     */
    private PrioUserData smallestValue(HashMap<Integer, PrioUserData> hm) {
        if (hm == null) {
            return null;
        }
        Iterator it = hm.entrySet().iterator();
        int ergPrio = 10000;
        PrioUserData ergUserData = null;
        while (it.hasNext()) {
            Map.Entry pairs = (Map.Entry) it.next();
            int actPrio = (Integer) pairs.getKey();
            PrioUserData actUserData = (PrioUserData) pairs.getValue();

            if (actPrio < ergPrio) {
                ergUserData = actUserData;
                ergPrio = actPrio;
            }
        }

        return ergUserData;
    }

    /**
     * This performs no processing but is required as the parent class is
     * abstract.
     */
    @Override
    public void updateScene(int xpos, int ypos) {}
}
